// -*- c-basic-offset: 2 default-tab-width: 2 indent-tabs-mode: t -*-
// vim: autoindent tabstop=2 noexpandtab shiftwidth=2 softtabstop=2
#ifndef _DEBUGGER_H_
#define _DEBUGGER_H_

#define BPOINTSBYWORD sizeof(word_t)

#include "bc.h"
#include "BuiltIns.h"
#include "Closure.h"

namespace R {
	class Evaluator;

	class Debugger {
		private:
			Evaluator *eval;
			word_t *breakpoints;
			int breakInstr[BC_LAST];
			int *cs;
			int pc;
			Stack *stack;
//			Environment *env;
		  EnvInfo* envInfo;
			CVector<Symbol*> *watches;

			int disassemble(int *cs, int startAt);
			word_t isBreakpoint(word_t pc) {
				return breakpoints[pc / BPOINTSBYWORD] & (1 << (pc % BPOINTSBYWORD));
			}

		public:
			Debugger(Evaluator *eval);  // Need to be called before calling checkBreakpoints
			void initMap(); // initialize functions map
			void activate(); // initialize internals of the debugger
			void checkBreakpoints() {
				int pc = eval->getPC() - 1;
				int bc = eval->getCS()[pc];
				if (breakInstr[bc] || isBreakpoint(pc)) /* FIXME breakpoints HAVE to be initialized */
					prompt();
			}

			static void getDebugger(Evaluator *eval){
				Debugger(eval).prompt();
			}

			void prompt();  // Debug machine

			// Returns a value > 0 if it is a function, takes command in parameter,
			// parse command name and sets pointer to first argument.
			// Returns negative value if cmd is an expression.
			//
			int isFunction(char** cmd);

			bool cmdHelp(char* cmd);
			bool cmdBreakpoint(char* cmd);
			bool cmdListNum(char* cmd);
			bool cmdExit(char* cmd);
			bool cmdExitDebbuger(char* cmd);
			bool cmdNext(char* cmd);
			bool cmdCompile(char* cmd);
			bool cmdPrintMap(char* cmd);
			bool cmdBuiltIn(char* cmd);
			bool cmdBuiltIns(char* cmd);
			bool cmdWatch(char* cmd);

			bool callCommand(int idx, char* cmd);
			void callExpression(char* cmd);


			void toggleBreakInstr(int iid);
			void toggleBreakInstr(char* instr);
			void setBreakpoint(word_t pc, word_t status);
			void toggleBreakpoint(int pc);
			void listBreakPoints();
			void showWatches();

			bool checkTrap(int pc, int val);
			void clearTrap(int val);
			void setTrap(int val);

			void displayBuiltInEntry(BuiltInMap* bim, int id = -1);

			void printStatusLine(const char* msg = "[info]");  // Debug machine
			void disassemble(int *cs, int startAt, int nb);
			void dumpTopStack(Stack* stack, bool deref, int n = 3);
			void dumpTopIntStack(Stack* stack, int nb = 3);
			void dumpTopCallStack(Stack* stack, int n = 3);
			void dumpTopEnvStack(Stack* stack, int n = 3);
	};
}

#endif
